/*
 * @Description: TODO
 * @Author: ZPS
 */

package sqlx

import (
	"errors"
	"fmt"
	"strings"
)

type NullType byte

type (
	Val = []any //Slice 类型的值统一使用Val类型
)

const (
	_ NullType = iota
	// IsNull the same as `is null`
	IsNull
	// IsNotNull the same as `is not null`
	IsNotNull

	Exp = "exp"
)

// WhereBuild sql build where 只接收map[string]any 和 [][]any类型
// where map[string]any key为字段名与操作符:字段名 操作符 ，value为字段值
// where [][]any [“字段名”,“操作符”,“查询值”,“与前一个条件的关系[默认and]”]
func WhereBuild(where any) (whereSQL string, vals []any, err error) {
	if obj, ok := where.(map[string]any); ok {
		return whereMapBuild(obj)
	}
	if obj, ok := where.([][]any); ok {
		return whereSliceBuild(obj)
	}
	return "", nil, fmt.Errorf("error in type: %v. ", where)
}

// sql build where
func whereMapBuild(where map[string]any) (whereSQL string, vals []any, err error) {
	for k, v := range where {
		ks := strings.Split(k, " ")
		if len(ks) > 2 {
			return "", nil, fmt.Errorf("Error in query condition: %s. ", k)
		}

		if whereSQL != "" {
			whereSQL += " AND "
		}
		switch len(ks) {
		case 1:
			k = fmt.Sprintf("`%s`", k)
			switch v := v.(type) {
			case NullType:
				if v == IsNotNull {
					whereSQL += fmt.Sprint(k, " IS NOT NULL")
				} else {
					whereSQL += fmt.Sprint(k, " IS NULL")
				}
			default:
				whereSQL += fmt.Sprint(k, " = ?")
				vals = append(vals, v)
			}
			break
		case 2:
			k = fmt.Sprintf("`%s`", ks[0])
			switch ks[1] {
			case "=":
				whereSQL += fmt.Sprint(k, " = ?")
				vals = append(vals, v)
			case ">":
				whereSQL += fmt.Sprint(k, " > ?")
				vals = append(vals, v)
			case ">=":
				whereSQL += fmt.Sprint(k, " >= ?")
				vals = append(vals, v)
			case "<":
				whereSQL += fmt.Sprint(k, " < ?")
				vals = append(vals, v)
			case "<=":
				whereSQL += fmt.Sprint(k, " <= ?")
				vals = append(vals, v)
			case "!=":
			case "<>":
				whereSQL += fmt.Sprint(k, " != ?")
				vals = append(vals, v)
			case "in":
				whereSQL += fmt.Sprint(k, " IN (?)")
				vals = append(vals, v)
			case "like":
				whereSQL += fmt.Sprint(k, " LIKE ?")
				vals = append(vals, v)
			case "between":
				whereSQL += fmt.Sprint(k, " BETWEEN ? AND ?")
				vals = append(vals, v.(Val)[:2]...)
			}
		}
	}
	return
}

// whereSliceBuild [“字段名”,“操作符”,“查询值”,“与前一个条件的关系[默认and]”]
// 1.如果是等于，可以省略"操作符" : []any{}{“username”, “chen”} 或 []any{}{“username”,"=" , “chen”}
// 2.大于: []any{}{“createtime”, “>”, “2019-1-1”}
// 3.如果为or，那就得一写全：[]any{}{“username”, “=”, “chen”, “or”}
// 4.其它的where兼容gorm的where方法
func whereSliceBuild(where [][]any) (whereSQL string, vals []any, err error) {
	for _, item := range where {
		count := len(item)
		if count < 2 || count > 4 {
			continue
		}
		if whereSQL != "" {
			// 默认and
			if count >= 4 {
				whereSQL += fmt.Sprintf(" %s ", item[3])
			} else {
				whereSQL += " AND "
			}
		}

		whereSQL += "("
		if count == 2 {
			whereSQL += fmt.Sprint(item[0], " = ?")
			vals = append(vals, item[1])
		} else {
			switch item[1] {
			case "between":
				whereSQL += fmt.Sprint(item[0], " BETWEEN ? AND ?")
				vals = append(vals, item[2].(Val)[:2]...)
			case Exp:
				valLen := strings.Count(item[0].(string), "?")
				if len(item[2].(Val)) != valLen {
					err = errors.New("exp ? Count Not equal to Val Count")
					return
				}
				whereSQL += item[0].(string)
				vals = append(vals, item[2].(Val)...)
			default:
				whereSQL += fmt.Sprintf("%s %s ?", item[0], item[1])
				vals = append(vals, item[2])
			}
		}
		whereSQL += ")"
	}
	if whereSQL == "" {
		err = errors.New("where is empty")
	}
	return
}
